#include <stdio.h>
#include <stdlib.h>

#include "..\src\srs\srs_librtmp.h"
#include "myThread.h"


int read_h264_frame(char* data, int size, char** pp, int* pnb_start_code, int fps,
	char** frame, int* frame_size, int* dts, int* pts)
{
	char* p = *pp;

	// @remark, for this demo, to publish h264 raw file to SRS,
	// we search the h264 frame from the buffer which cached the h264 data.
	// please get h264 raw data from device, it always a encoded frame.
	if (!srs_h264_startswith_annexb(p, size - (p - data), pnb_start_code)) {
		srs_human_trace("h264 raw data invalid.");
		return -1;
	}

	// @see srs_write_h264_raw_frames
	// each frame prefixed h.264 annexb header, by N[00] 00 00 01, where N>=0,
	// for instance, frame = header(00 00 00 01) + payload(67 42 80 29 95 A0 14 01 6E 40)
	*frame = p;
	p += *pnb_start_code;

	for (; p < data + size; p++) {
		if (srs_h264_startswith_annexb(p, size - (p - data), NULL)) {
			break;
		}
	}

	*pp = p;
	*frame_size = p - *frame;
	if (*frame_size <= 0) {
		srs_human_trace("h264 raw data invalid.");
		return -1;
	}

	// @remark, please get the dts and pts from device,
	// we assume there is no B frame, and the fps can guess the fps and dts,
	// while the dts and pts must read from encode lib or device.
	*dts += 1000 / fps;
	*pts = *dts;

	return 0;
}

int read_audio_frame(char* data, int size, char** pp, char** frame, int* frame_size)
{
	char* p = *pp;

	// @remark, for this demo, to publish aac raw file to SRS,
	// we search the adts frame from the buffer which cached the aac data.
	// please get aac adts raw data from device, it always a encoded frame.
	if (!srs_aac_is_adts(p, size - (p - data))) {
		srs_human_trace("aac adts raw data invalid.");
		return -1;
	}

	// @see srs_audio_write_raw_frame
	// each frame prefixed aac adts header, '1111 1111 1111'B, that is 0xFFF.,
	// for instance, frame = FF F1 5C 80 13 A0 FC 00 D0 33 83 E8 5B
	*frame = p;
	// skip some data.
	// @remark, user donot need to do this.
	p += srs_aac_adts_frame_size(p, size - (p - data));

	*pp = p;
	*frame_size = p - *frame;
	if (*frame_size <= 0) {
		srs_human_trace("aac adts raw data invalid.");
		return -1;
	}

	return 0;
}

char* h265_raw = NULL;
char* adts_raw = NULL;

void function()
{
	char* ph265_raw = h265_raw;
	char* padts_raw = adts_raw;


}

int main(int argc, char** argv)
{
	const char* raw_file_h265 = "C:/GITEE_PRO/srs-librtmp/vs2015/input.h265";
	const char* raw_file_adts = "C:/GITEE_PRO/srs-librtmp/vs2015/input.adts";
	const char* rtmp_url = "rtmp://192.168.2.77:1935/live/livestream";
	//const char* rtmp_url = "rtmp://127.0.0.1:1935/live/livestream";

	srs_rtmp_t rtmp = NULL;
	// @remark, the dts and pts if read from device, for instance, the encode lib,
	// so we assume the fps is 25, and each h264 frame is 1000ms/25fps=40ms/f.
	double fps = 25;
	srs_human_trace("raw_file=%s, rtmp_url=%s, fps=%.2f", raw_file_h265, rtmp_url, fps);

	// open file
	FILE* raw_fd_h265 = NULL;
	FILE* raw_fd_adts = NULL;
	errno_t err1 = fopen_s(&raw_fd_h265, raw_file_h265, "rb");
	errno_t err2 = fopen_s(&raw_fd_adts, raw_file_adts, "rb");
	if (err1 || err2) {
		srs_human_trace("open h264 raw file %s failed.", raw_file_h265);
		goto rtmp_destroy;
	}
	{
		fseek(raw_fd_h265, 0, SEEK_END);
		fseek(raw_fd_adts, 0, SEEK_END);
		off_t h265_file_size = ftell(raw_fd_h265);
		off_t adts_file_size = ftell(raw_fd_adts);
		if (h265_file_size <= 0 || adts_file_size <= 0) {
			srs_human_trace("h264 raw file %s empty.", raw_file_h265);
			goto rtmp_destroy;
		}
		srs_human_trace("read entirely h264 raw file, size=%dKB", (int)(h265_file_size / 1024));

		h265_raw = (char*)malloc(h265_file_size);
		adts_raw = (char*)malloc(adts_file_size);
		if (!h265_raw || !adts_raw) {
			srs_human_trace("alloc raw buffer failed for file %s.", raw_file_h265);
			goto rtmp_destroy;
		}

		fseek(raw_fd_h265, 0, SEEK_SET);
		fseek(raw_fd_adts, 0, SEEK_SET);

		ssize_t nb_read = 0;
		if ((nb_read = fread(h265_raw, 1, h265_file_size, raw_fd_h265)) != h265_file_size) {
			srs_human_trace("buffer %s failed, expect=%dKB, actual=%dKB.",
				raw_file_h265, (int)(h265_file_size / 1024), (int)(nb_read / 1024));
			goto rtmp_destroy;
		}
		if ((nb_read = fread(adts_raw, 1, adts_file_size, raw_fd_adts)) != adts_file_size) {
			srs_human_trace("buffer %s failed, expect=%dKB, actual=%dKB.",
				raw_file_adts, (int)(adts_file_size / 1024), (int)(nb_read / 1024));
			goto rtmp_destroy;
		}
		// connect rtmp context
		rtmp = srs_rtmp_create(rtmp_url);

		if (srs_rtmp_handshake(rtmp) != 0) {
			srs_human_trace("simple handshake failed.");
			goto rtmp_destroy;
		}
		srs_human_trace("simple handshake success");

		if (srs_rtmp_connect_app(rtmp) != 0) {
			srs_human_trace("connect vhost/app failed.");
			goto rtmp_destroy;
		}
		srs_human_trace("connect vhost/app success");

		if (srs_rtmp_publish_stream(rtmp) != 0) {
			srs_human_trace("publish stream failed.");
			goto rtmp_destroy;
		}
		srs_human_trace("publish stream success");

		int dts = 0;
		int pts = 0;
		// @remark, to decode the file.
		char* p1 = h265_raw;
		char* p2 = adts_raw;
		int count = 0;

		uint32_t timestamp = 0;
		uint32_t time_delta = 45;
		for (; p1 < h265_raw + h265_file_size && p2 < adts_raw + adts_file_size;) {
			// @remark, read a frame from file buffer.
			char* data1 = NULL;
			char* data2 = NULL;
			int size1 = 0;
			int size2 = 0;
			int nb_start_code = 0;
			if (read_h264_frame(h265_raw, h265_file_size, &p1, &nb_start_code, fps, &data1, &size1, &dts, &pts) < 0) {
				srs_human_trace("read a frame from file buffer failed.");
				goto rtmp_destroy;
			}
			if (read_audio_frame(adts_raw, adts_file_size, &p2, &data2, &size2) < 0) {
				srs_human_trace("read a frame from file buffer failed.");
				goto rtmp_destroy;
			}
			// send out the h265 packet over RTMP
			int ret = srs_h265_write_raw_frames(rtmp, data1, size1, dts, pts);
			if (ret != 0) {
				if (srs_h264_is_dvbsp_error(ret)) {
					srs_human_trace("ignore drop video error, code=%d", ret);
				}
				else if (srs_h264_is_duplicated_sps_error(ret)) {
					srs_human_trace("ignore duplicated sps, code=%d", ret);
				}
				else if (srs_h264_is_duplicated_pps_error(ret)) {
					srs_human_trace("ignore duplicated pps, code=%d", ret);
				}
				else {
					srs_human_trace("send h264 raw data failed. ret=%d", ret);
					goto rtmp_destroy;
				}
			}

			// 5bits, 7.3.1 NAL unit syntax,
			// ISO_IEC_14496-10-AVC-2003.pdf, page 44.
			//  7: SPS, 8: PPS, 5: I Frame, 1: P Frame, 9: AUD, 6: SEI
			uint8_t nut = (char)data1[nb_start_code] & 0x7E >> 1;
			srs_human_trace("sent packet: type=%s, time=%d, size=%d, fps=%.2f, b[%d]=%#x(%s)",
				srs_human_flv_tag_type2string(SRS_RTMP_TYPE_VIDEO), dts, size1, fps, nb_start_code, (char)data1[nb_start_code],
				(nut == 32 ? "VPS" : (nut == 33 ? "SPS" : (nut == 34 ? "PPS" : (nut == 1 ? "P" : (nut == 9 ? "AUD" : (nut == 6 ? "SEI" : "Unknown")))))));

			timestamp += time_delta;
			if ((ret = srs_audio_write_raw_frame(rtmp, 10, 2, 1, 1, data2, size2, timestamp)) != 0) {
				srs_human_trace("send audio raw data failed. ret=%d", ret);
				goto rtmp_destroy;
			}
			srs_human_trace("sent packet: type=%s, time=%d, size=%d, codec=%d, rate=%d, sample=%d, channel=%d",
				srs_human_flv_tag_type2string(SRS_RTMP_TYPE_AUDIO), timestamp, size2, 10, 2, 1,
				1);
			// @remark, when use encode device, it not need to sleep.
			if (count++ == 9) {
				usleep(1000 * 1000 * count / fps);
				count = 0;
			}
		}
		srs_human_trace("h264 raw data completed");
	}
rtmp_destroy:
	srs_rtmp_destroy(rtmp);
	fclose(raw_fd_h265);
	fclose(raw_fd_adts);
	free(h265_raw);
	free(adts_raw);

	return 0;
}

